﻿using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using ClosedXML.Excel;
using Haimen.Excel;

namespace Haimen.Func1;

internal class HuallExportMerger(
    GroupConfigReader groupCfgReader,
    AppConfigReader appCfgReader,
    HuallDataLoader dataLoader,
    ExcelFileUtils excelUtil) {

  public string[] Merge(AppEnvPath envPath) {
    string inDir = envPath.In();
    string lookupPath = ResolveLookupPath(envPath);
    Console.WriteLine("--indindir " + inDir);

    // 获取数据源sheet名
    (DataGroupCfg[] groupAll, string outPath) = PrepareOutput(envPath);

    // 按sheet名把文件路径分组
    string[] fileList = Directory.GetFiles(inDir);
    Trace.Assert(fileList.Length > 0);

    (string path, string name)[] inFiles = fileList.Order()
      .Select(p => (p, Path.GetFileNameWithoutExtension(p) ?? ""))
      .ToArray();

    var GetGroup = (string group) => inFiles
      .Where(f => f.name.StartsWith(group))
      .Select(f => f.path)
      .ToArray();

    (string name, string[] path)[] groupPath = groupAll
      .Select(g => g.Name)
      .Select(g => (g, GetGroup(g)))
      .ToArray();

    // 并发读取文件数据
    AppConfigRoot config = _appCfgReader.Read(groupAll, lookupPath);
    var ReadGroup = (string[] paths, string group) => paths
      .Select(p => Task.Run(() => _dataLoader.Load(p, group, config)))
      .ToArray();

    (string group, Task<HuallLoadResult>[])[] groupLoading = groupPath
      .Where(g => g.path.Length > 0)
      .Select(g => (g.name, ReadGroup(g.path, g.name)))
      .ToArray();

    // 按组写入对应sheet
    WriteToOutput(outPath, groupLoading).Wait();

    return groupLoading
      .Select(g => g.group)
      .ToArray();
  }

  string ResolveLookupPath(AppEnvPath path) {
    const string lookup = "vlookup.xlsx";
    string dev = path.InDev(lookup);

    if (!File.Exists(dev)) {
      return path.ResFunc1(lookup);
    }
    Console.WriteLine($"检测到dev：{dev}");
    return dev;
  }

  (DataGroupCfg[], string) PrepareOutput(AppEnvPath path) {
    string templatePath = path.ResFunc1("load.xlsx");
    string outPath = path.OutDir(path.Merge);
    File.Copy(templatePath, outPath, overwrite: true);

    DataGroupCfg[] groupList = _groupCfgReader.Read(outPath);
    return (groupList, outPath);
  }

  async Task WriteToOutput(string outPath, (string group, Task<HuallLoadResult>[])[] groupLoad) {
    using FileStream stream = _excelUtil.OpenWrite(outPath);
    using XLWorkbook outBook = new(stream);

    foreach ((string group, Task<HuallLoadResult>[] loadList) in groupLoad) {
      Debug.Assert(loadList.Length > 0);
      IXLWorksheet sheet = outBook.Worksheet(group);

      int rowCursor = 2; // 多个表要往下续写
      foreach (Task<HuallLoadResult> loading in loadList) {
        HuallLoadResult result = await loading;
        Console.WriteLine(result.Name);

        foreach (HuallMergeRow row in result.Rows) {
          object[] colVal = row.ColVal;
          for (int c = 0; c < colVal.Length; c++) {
            XLCellValue cellVal = ToCellVal(colVal[c]);
            sheet.Cell(rowCursor, c + 1).SetValue(cellVal);
          }
          rowCursor++;
        }
      }
    }

    string lastWrite = groupLoad[^1].group;
    foreach (IXLWorksheet sheet in outBook.Worksheets) {
      bool active = lastWrite.Equals(sheet.Name);
      sheet.SetTabSelected(active);
      sheet.SetTabActive(active);
    }

    outBook.Save();
  }

  XLCellValue ToCellVal(object val) {
    if (val is int valInt) {
      return (XLCellValue)valInt;
    }
    if (val is double valDoub) {
      return (XLCellValue)valDoub;
    }

    string valStr = (string)val;
    if (DateTime.TryParseExact(valStr, "yyyy-MM-dd",
        CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime varDate)) {
      return (XLCellValue)varDate;
    }

    return (XLCellValue)valStr;
  }

  readonly GroupConfigReader _groupCfgReader = groupCfgReader;
  readonly AppConfigReader _appCfgReader = appCfgReader;

  readonly HuallDataLoader _dataLoader = dataLoader;
  readonly ExcelFileUtils _excelUtil = excelUtil;
}
